/**
 * 
 */
package merisis.silo;

import static java.lang.System.arraycopy;
import static merisis.silo.CakedCursorUtil.MAX_SLOT_NUM;

public class IndexedNode {

	int leftSameness = 0;

	String[] stringSeq;

	private byte top = -1;

	private byte slotnum;

	private Object[] slots = new Object[MAX_SLOT_NUM];

	public byte getSize() {

		return slotnum;
	}

	public Object get(int idx) {

		return get((byte) idx);
	}

	public Object get(byte idx) {

		return slots[idx];
	}

	public void put(byte idx, Object obj) {

		if (slots[idx] == null) {
			if (obj != null) {
				slotnum++;
				if (idx > top)
					top = idx;
			}
		} else {
			if (obj == null) {
				slotnum--;
				if (idx == top) {
					do {
						top--;
					} while (top >= 0 && slots[top] == null);
				}
			}
		}

		slots[idx] = obj;
	}

	public void insert(int pos, Object obj) {

		insert((byte) pos, obj);
	}

	public void insert(byte pos, Object obj) {

		// TODO THREADSAFE
		if (pos <= top) {

			if (top + 1 >= MAX_SLOT_NUM)
				throw new ArrayIndexOutOfBoundsException(
						"reach the bottom: tailIndex=" + top);

			// move a slot
			arraycopy(slots, pos, slots, pos + 1, (top - pos + 1));
			top++;

			if (obj != null)
				slotnum++;

			slots[pos] = obj;
		} else {

			// append a value
			put((byte) (top + 1), obj);
		}
	}

	public Object getHeadObject() {
		return get((byte) 0);
	}

	public void putHeadObject(Object obj) {

		put((byte) 0, obj);
	}

	public boolean isEmpty() {

		return slotnum == 0;
	}

	public boolean isFull() {

		return top + 1 == MAX_SLOT_NUM;
	}

	public boolean hasFreeSlot() {

		return slotnum < MAX_SLOT_NUM;
	}

	public Object getTail() {

		if (top == -1)
			return null;

		return slots[top];
	}

	public byte getTop() {

		return top;
	}

	public static byte boundaryTop() {

		return MAX_SLOT_NUM - 1;
	}

	public Object getBottomObject() {

		return slots[MAX_SLOT_NUM - 1];
	}

	public boolean hasEnoughFreeSlot(byte num) {
		
		return num <= boundaryTop() - getTop();
	}

	public void takeLatterPart(int destPos, IndexedNode src, int srcPos) {

		takeLatterPart((byte) destPos, src, (byte) srcPos);
	}

	public void takeLatterPart(byte destPos, IndexedNode src, byte srcPos) {

		if (destPos > srcPos)
			throw new ArrayIndexOutOfBoundsException(String.format(
					"dest > src: %d > %d", destPos, srcPos));

		final byte srcTop = src.top;
		final byte srcLen = (byte) (srcTop - srcPos + 1);

		if (destPos <= top) {

			for (byte i = top; i >= destPos; i--) {
				slots[i + srcLen] = slots[i];
			}
			this.top += srcLen;
			this.slotnum += srcLen;
		}
		if (srcLen < 0) {
			throw new RuntimeException();
		}

		Object[] objs = new Object[srcLen];
		int count = 0;
		for (byte k = srcPos; k <= srcTop; k++) {

			Object obj = src.get(k);
			if (obj != null) {

				objs[count] = obj;
				src.put(k, null);
				count++;
			}
		}

		for (byte k = 0; k < count; k++) {

			put(destPos, objs[k]);
			destPos++;
		}
	}

	public static IndexedNode allocate() {
		return new IndexedNode();
	}
}